import { __private, _decorator, Node, ResolutionPolicy, SafeArea, screen, view } from "cc";
import { UI2DFragmnet } from "./fragment/UI2DFragmnet";
import { UIFragment } from "./fragment/UIFragment";
import { PopUpFragment } from "./fragment/PopUpFragment";
import { DialogFragment } from "./fragment/DialogFragment";
import { NotifyFragment } from "./fragment/NotifyFragment";
import { Fragment } from "./fragment/Fragment";
import { Constructor } from "./pool/NodeGroup";
import View from "./view/View";
import { AssetManager } from "cc";
import { resources } from "cc";

/**
 * 层数越高,越在上层
 */
export enum Layer {
    /** 二维游戏层 */
    Game,
    /** 主界面层 */
    UI,
    /** 弹窗层 */
    Popup,
    /** 模式窗口层 */
    Dialog,
    /** 系统触发模式窗口层 */
    System,
    /** 消息提示层 */
    Notify,
    /** 新手引导层 */
    Guide,
}

export interface AddListener {

    onAddBefore?: (manager: FragmentManager, view: View, node: Node, root: Node, params: {}) => Promise<void>;

    onAdd?: (manager: FragmentManager, view: View, node: Node) => void;

}

export interface RemoveListener {

    onRemoveBefore?: (manager: FragmentManager, view: View, node: Node, root: Node, params: {}) => Promise<void>;

    onRemove?: (manager: FragmentManager, view: View, node: Node, destroy: boolean) => void;

}

export class Config {
    timeout: number = 1000;
    defauleBundle: string | AssetManager.Bundle = resources;
}

export default class FragmentManager {

    private uid: number = 0;

    /** 界面配置 */
    readonly config: Config;

    /** 界面根节点 */
    readonly root: Node;

    /** 图层管理 */
    private fragments: Fragment[] = [];

    /** View管理 */
    private views: Map<Constructor<View>, View[]> = new Map();

    /** 窗口宽高比例 */
    windowAspectRatio: number = 0;

    /** 设计宽高比例 */
    designAspectRatio: number = 0;

    /** 是否开启移动设备安全区域适配 */
    mobileSafeArea: boolean = false;

    constructor(node: Node, config: Config) {
        this.root = node;
        this.config = config;
        this.initFragment(node);
        this.initScreenAdapter();
    }

    protected initFragment(root: Node) {
        this.fragments.push(
            new UI2DFragmnet(Layer.Game, 'Game'),
            new UIFragment(Layer.UI, 'UI'),
            new PopUpFragment(Layer.Popup, 'Popup'),
            new DialogFragment(Layer.Dialog, 'Dialog'),
            new DialogFragment(Layer.System, 'System'),
            new NotifyFragment(Layer.Notify, 'Notify'),
            new UI2DFragmnet(Layer.Guide, 'Guide'),
        )
        for (const fragment of this.fragments) {
            root.addChild(fragment);
        }
    }

    protected getFragment(layer: number | Layer) {
        if (layer >= this.fragments.length) {
            throw `getFragment::error index is ${layer} , length = ${this.fragments.length}`
        }
        return this.fragments[layer];
    }

    /** 初始化屏幕适配 */
    initScreenAdapter() {
        const drs = view.getDesignResolutionSize();
        const ws = screen.windowSize;
        this.windowAspectRatio = ws.width / ws.height;
        this.designAspectRatio = drs.width / drs.height;

        let finalW: number = 0;
        let finalH: number = 0;

        if (this.windowAspectRatio > this.designAspectRatio) {
            finalH = drs.height;
            finalW = finalH * ws.width / ws.height;
            console.log("适配屏幕高度", "【横屏】")
        }
        else {
            finalW = drs.width;
            finalH = finalW * ws.height / ws.width;
            console.log("适配屏幕宽度", "【竖屏】");
        }
        view.setDesignResolutionSize(finalW, finalH, ResolutionPolicy.UNKNOWN);

        if (this.mobileSafeArea) {
            this.root.addComponent(SafeArea);
            console.log("开启移动设备安全区域适配");
        }
    }

    toast(content: string, useI18n: boolean = false) {
        const fragmnet = this.getFragment(Layer.Notify);
        if (fragmnet instanceof NotifyFragment) {
            fragmnet.show(this, content, useI18n);
        }
    }

    /** 打开等待提示 */
    waitOpen() {
        // this.notify.waitOpen();
    }

    /** 关闭等待提示 */
    waitClose() {
        // this.notify.waitClose();
    }

    openSingle<T extends View>(view: Constructor<T>, listener?: AddListener, params?: any): Promise<[View, Node] | null> {
        // 判断是否可重复加载
        if (this.views.has(view)) {
            console.warn(`View为【${view.name}】的重复加载`);
            return Promise.resolve(null);
        }
        return this.open(view, listener, params);
    }

    open<T extends View>(view: Constructor<T>, listener?: AddListener, params?: any): Promise<[View, Node] | null> {
        const viewImpl = new view(`${view.name}[${this.uid++}]`);
        // 获取对应的LayerFragment
        const layer = this.getFragment(viewImpl.layer());
        if (layer) {
            return layer.addView(this, viewImpl, listener, params).then((result) => {
                if (result) {
                    this.bindView(viewImpl);
                    return Promise.resolve([viewImpl, result]);
                } else {
                    return Promise.resolve(null);
                }
            });
        } else {
            throw 'openAsync::Error::can not find layer by ' + viewImpl.layer;
        }
    }

    bindView<T extends View>(view: T) {
        const key = view.constructor as Constructor<T>;
        let viewArray = this.views.get(key);
        if (!viewArray) {
            viewArray = [];
            this.views.set(key, viewArray);
        }
        viewArray.push(view);
    }

    has(view: Constructor<View> | View) {
        if (view instanceof View) {
            const viewArray = this.views.get(view.constructor as Constructor<View>);
            return viewArray && viewArray.indexOf(view) >= 0;
        }
        return this.views.has(view);
    }

    remove(view: Constructor<View> | View, destroy: boolean = true, params: {} = {}) {
        if (view instanceof View) {
            const key = view.constructor as Constructor<View>;
            const viewImpl = this.views.get(key);
            if (viewImpl) {
                const idx = viewImpl.indexOf(view);
                if (idx >= 0) {
                    const layer = this.getFragment(view.layer());
                    layer.removeView(this, view, destroy, params);
                    viewImpl.splice(idx, 1);
                } else {
                    console.log('remove::not find viewImpl by array', viewImpl);
                }
                if (viewImpl.length <= 0) {
                    this.views.delete(key);
                }
            } else {
                console.log('remove::not find viewImpl class ', view.constructor.name);
            }
        } else {
            const viewImpl = this.views.get(view);
            if (viewImpl) {
                for (const view of viewImpl) {
                    const layer = this.getFragment(view.layer())
                    layer.removeView(this, view, destroy, params);
                }
                this.views.delete(view);
            } else {
                console.log('remove::not find viewImpl by ', view.name);
            }
        }
    }

    clear(destroy: boolean = false) {
        for (const fragment of this.fragments) {
            fragment.clear(this, destroy)
        }
    }
}